import thread

class SubscriptionTree(object):
    
    def __init__(self):
        
        self.root = _Node('/')
        self.treelock = thread.allocate_lock()
        
    def _find_node(self,path):
        
        root = self.root        
        nodes = path.split('/')
        for node in nodes:
            if node != '':
                if not root.children.has_key(node):
                    root.children[node] = _Node(node)
                root = root.children[node]
        return root
    
    def add_node(self,path,node):
        self.treelock.acquire()
        parentnode = self._find_node(path)
        if not parentnode.children.has_key(node):
            parentnode.children[node] = _Node(node)
        self.treelock.release()
        
    def delete_node(self,path,node):
        self.treelock.acquire()
        parentnode = self._find_node(path)
        if parentnode.children.has_key(node):
            if len(parentnode.children[node].subscribers) == 0:
                del parentnode.children[node]
        self.treelock.release()
    
    def add_subscriber(self,path,subscriber):
        self.treelock.acquire()
        parentnode = self._find_node(path)
        parentnode.subscribers.append(subscriber)
        self.treelock.release()
        print str(self)
        
    def delete_subscriber(self,path,subscriber):
        self.treelock.acquire()
        parentnode = self._find_node(path)
        if subscriber in parentnode.subscribers:
            parentnode.subscribers.remove(subscriber)
        self.treelock.release()
        print str(self)
    
    def add_monitor(self,path,monitortype,monitor):
        self.treelock.acquire()
        parentnode = self._find_node(path)
        if not parentnode.monitors.has_key(monitortype):
            parentnode.monitors[monitortype] = []
        parentnode.monitors[monitortype].append(monitor)
        self.treelock.release()
        
    def delete_monitor(self,path,monitortype,monitor):
        self.treelock.acquire()
        parentnode = self._find_node(path)
        if parentnode.monitors.has_key(monitortype) and monitor in parentnode.monitors[monitortype]:
            parentnode.monitors[monitortype].remove(monitor)
            if len(parentnode.monitors[monitortype]) == 0:
                del parentnode.monitors[monitortype]
        self.treelock.release()
        
    def notify_subscribers(self,path,message):
        self.treelock.acquire()
        parentnode = self._find_node(path)
        for subscriber in parentnode.subscribers:
            try:
                subscriber(message)
            except: pass
        self.treelock.release()
    
    def notify_monitors(self,path,monitortype,message):
        self.treelock.acquire()
        parentnode = self._find_node(path)
        if parentnode.monitors.has_key(monitortype):
            for monitor in parentnode.monitors[monitortype]:
                try:
                    monitor(message)
                except: pass                  
        self.treelock.release()
        
    def __str__(self):
        return str(self.root)
        
class _Node(object):
    
    def __init__(self,name):
        
        self.name = name
        self.subscribers = []
        self.monitors = {}
        self.children = {}
        
    def __str__(self):
        return self.to_string()
    
    def to_string(self,level=-1):
        
        returnstring =  str('\t' * level) + str(self.name)
        if self.name[-1:] != '/':
            returnstring = ''.join((returnstring,'/'))
        if len(self.subscribers) > 0:
            returnstring = ''.join((returnstring,'\n',str('\t' * level),'<Subscribers>'))
            for subscriber in self.subscribers:
                returnstring = ''.join((returnstring,'\n',str('\t' * (level)),'  ',str(subscriber)))
            returnstring = ''.join((returnstring,'\n',str('\t' * level),'</Subscribers>'))
        else:
            returnstring = ''.join((returnstring,'\n'))
        if len(self.monitors) > 0:
            returnstring = ''.join((returnstring,'\n',str('\t' * (level)),'<Monitors>'))
            for key,monitortype in self.monitors.iteritems():
                returnstring = ''.join((returnstring,'\n',str('\t' * (level)),'<',key,'>'))
                for monitor in monitortype:
                    returnstring = ''.join((returnstring,'\n',str('\t' * (level)),'  ', str(monitor)))
                returnstring = ''.join((returnstring,'\n',str('\t' * (level)),'</',key,'>'))
            returnstring = ''.join((returnstring,'\n',str('\t' * level),'</Monitors>'))    
        else:
            returnstring = ''.join((returnstring,'\n'))
        for child in self.children.itervalues():
            returnstring = ''.join((returnstring,child.to_string(level=level+1)))
        
        return returnstring

class StupidClass(object):
    def __init__(self,name):
        self.name = name
    
    def handler(self,message):
        print 'I am a StupidClass %s. Here is my message: %s' % (str(self.name) ,message)
        
    def monitor_handler(self,message):
        print 'I am a StupidClass %s monitor_handler. Here is my message: %s' % (str(self.name),message)
        
def subscriber(message):
    print 'I am a subscriber. Here is my message: ' + message
   
if __name__ == '__main__':
    
    subtree = SubscriptionTree()
    
    subtree.add_node('/', 'Applications')
    subtree.add_node('/Applications/','Chat')
    subtree.add_node('/Applications/Chat/','Rooms')
    
    sc = StupidClass('1')
    sc1 = StupidClass('2')
    sc2 = StupidClass('3')
    subtree.add_subscriber('/Applications/Chat/Rooms', sc.handler)
    subtree.add_subscriber('/Applications/Chat/Rooms', sc1.handler)
    subtree.add_subscriber('/Applications/Chat/Rooms', sc2.handler)
    
    subtree.notify_subscribers('/Applications/Chat/Rooms/','Welcome to my room')
    print subtree
    subtree.delete_subscriber('/Applications/Chat/Rooms/', sc1.handler)
    print subtree
    subtree.notify_subscribers('/Applications/Chat/Rooms/','Welcome to my room')
    
    subtree.add_monitor('/Applications/Chat/Rooms/', 'Get', sc1.monitor_handler)
    print subtree
    subtree.notify_monitors('/Applications/Chat/Rooms/', 'Get', 'You are monitoring Gets')